#pragma once
#include "../source/server.hpp"
#include <fstream>
#include <sys/stat.h>
#include <regex>

#define DEFAULT_TIMEOUT 30

class Util
{
public:
    // 字符串分割函数
    static size_t Split(const std::string &src, const std::string &sep, std::vector<std::string> &array)
    {
        size_t offset = 0;
        // 从src字符串的偏移量offset位置开始查找sep分隔符
        while (offset < src.size())
        {
            size_t pos = src.find(sep, offset);
            if (pos == std::string::npos)
            {
                array.emplace_back(src.substr(offset)); // 将最后一个字符串放入
                return array.size();
            }
            if (offset < pos)
                array.emplace_back(src.substr(offset, pos - offset));
            offset = pos + sep.size();
        }
        return array.size();
    }
    // 读取文件内容
    static bool ReadFile(const std::string &filename, Buffer &buff)
    {
        std::ifstream ifs(filename, std::ios::binary); // 输入文件流
        if (ifs.is_open() == false)
        {
            ERROR_LOG("打开文件失败:%s", filename.c_str());
            return false;
        }
        size_t fsize = 0;
        ifs.seekg(0, ifs.end); // 调整读写位置为文件的末尾偏移量为0处（末尾不是文件的最后一个元素，是最后一个元素的后一位）
        fsize = ifs.tellg();   // 总长度就是当前读写位置的偏移量,例如"a"，调整位置为文件末尾即'a'的后面，那么偏移量就是1
        ifs.seekg(0, ifs.beg); // 将读写位置调回文件起始位置偏移量0处
        std::string buffer;
        buffer.resize(fsize);
        ifs.read((char *)buffer.c_str(), fsize);
        if (ifs.good() == false)
        {
            ERROR_LOG("文件读取失败:%s", filename.c_str());
            return false;
        }
        buff.WriteAndPush(buffer.c_str(), fsize);
        return true;
    }
    static bool ReadFile(const std::string &filename, std::string& buf)
    {
        std::ifstream ifs(filename, std::ios::binary); // 输入文件流
        if (ifs.is_open() == false)
        {
            ERROR_LOG("打开文件失败:%s", filename.c_str());
            return false;
        }
        size_t fsize = 0;
        ifs.seekg(0, ifs.end); // 调整读写位置为文件的末尾偏移量为0处（末尾不是文件的最后一个元素，是最后一个元素的后一位）
        fsize = ifs.tellg();   // 总长度就是当前读写位置的偏移量,例如"a"，调整位置为文件末尾即'a'的后面，那么偏移量就是1
        ifs.seekg(0, ifs.beg); // 将读写位置调回文件起始位置偏移量0处
        buf.resize(fsize);
        ifs.read(&buf[0], fsize);
        if (ifs.good() == false)
        {
            ERROR_LOG("文件读取失败:%s", filename.c_str());
            return false;
        }
        return true;
    }
    // 向文件写入数据
    static bool WriteFile(const std::string &filename,Buffer &buff)
    {
        std::ofstream ofs(filename);
        if (ofs.is_open() == false)
        {
            ERROR_LOG("打开文件失败:%s", filename.c_str());
            return false;
        }
        ofs.write(buff.Read_Position(), buff.ReadAbleSize());
        if (ofs.good() == false)
        {
            ERROR_LOG("文件读取失败:%s", filename.c_str());
            return false;
        }
        return true;
    }
    static bool WriteFile(const std::string &filename, const std::string &buff)
    {
        std::ofstream ofs(filename);
        if (ofs.is_open() == false)
        {
            ERROR_LOG("打开文件失败:%s", filename.c_str());
            return false;
        }
        ofs.write(buff.c_str(), buff.size());
        if (ofs.good() == false)
        {
            ERROR_LOG("文件读取失败:%s", filename.c_str());
            return false;
        }
        return true;
    }
    // URL编码
    // RFC3986标准中规定编码格式:%HH
    // 为避免url资源路径与查询字符串中的特殊字符与HTTP请求中特殊字符产生歧义
    // 不编码的特殊字符：'.','-','_','~'，字母，数字
    // W3C标准规定，查询字符串中的空格，需要编码为'+'
    // 以上两个标准一起执行
    static std::string URLEncode(const std::string &url, bool convert_space_to_plus)
    {
        std::string res;
        for (auto &e : url)
        {
            if (e == '.' || e == '-' || e == '_' || e == '~' || isalnum(e) || isupper(e) || islower(e))
            {
                res += e;
                continue;
            }
            else if (e == ' ' && convert_space_to_plus)
            {
                res += '+';
                continue;
            }
            char tmp[4];
            snprintf(tmp, 4, "%%%02X", e); // x是转换为16进制是字母小写，X则是大写
            res += tmp;
        }
        return res;
    }
    static int HexToI(char c)
    {
        if (c >= '0' && c <= '9')
            return c - '0';
        else if (c >= 'a')
            return c - 'a' + 10;
        return c - 'A' + 10;
    }
    // URL解码
    static std::string URLDecode(const std::string &url, bool convert_space_to_plus)
    {
        std::string res;
        for (int i = 0; i < url.size(); ++i)
        {
            if (url[i] == '%')
            {
                char v = (HexToI(url[i + 1]) << 4) + (HexToI(url[i + 2]));
                res += v;
                i += 2;
            }
            else if (url[i] == '+' && convert_space_to_plus)
                res += ' ';
            else
                res += url[i];
        }
        return res;
    }
    // 响应状态码描述获取
    static std::string StatusDesc(int status)
    {
        // 静态哈希表存储所有HTTP状态码与描述
        static std::unordered_map<int, std::string> status_msg = {
            // 1xx 信息响应
            {100, "Continue"},
            {101, "Switching Protocols"},
            {102, "Processing"},
            {103, "Early Hints"},

            // 2xx 成功响应
            {200, "OK"},
            {201, "Created"},
            {202, "Accepted"},
            {203, "Non-Authoritative Information"},
            {204, "No Content"},
            {205, "Reset Content"},
            {206, "Partial Content"},
            {207, "Multi-Status"},
            {208, "Already Reported"},
            {226, "IM Used"},

            // 3xx 重定向
            {300, "Multiple Choices"},
            {301, "Moved Permanently"},
            {302, "Found"},
            {303, "See Other"},
            {304, "Not Modified"},
            {305, "Use Proxy"},
            {306, "Switch Proxy"},
            {307, "Temporary Redirect"},
            {308, "Permanent Redirect"},

            // 4xx 客户端错误
            {400, "Bad Request"},
            {401, "Unauthorized"},
            {402, "Payment Required"},
            {403, "Forbidden"},
            {404, "Not Found"},
            {405, "Method Not Allowed"},
            {406, "Not Acceptable"},
            {407, "Proxy Authentication Required"},
            {408, "Request Timeout"},
            {409, "Conflict"},
            {410, "Gone"},
            {411, "Length Required"},
            {412, "Precondition Failed"},
            {413, "Payload Too Large"},
            {414, "URI Too Long"},
            {415, "Unsupported Media Type"},
            {416, "Range Not Satisfiable"},
            {417, "Expectation Failed"},
            {418, "I'm a teapot"},
            {421, "Misdirected Request"},
            {422, "Unprocessable Entity"},
            {423, "Locked"},
            {424, "Failed Dependency"},
            {425, "Too Early"},
            {426, "Upgrade Required"},
            {428, "Precondition Required"},
            {429, "Too Many Requests"},
            {431, "Request Header Fields Too Large"},
            {451, "Unavailable For Legal Reasons"},

            // 5xx 服务器错误
            {500, "Internal Server Error"},
            {501, "Not Implemented"},
            {502, "Bad Gateway"},
            {503, "Service Unavailable"},
            {504, "Gateway Timeout"},
            {505, "HTTP Version Not Supported"},
            {506, "Variant Also Negotiates"},
            {507, "Insufficient Storage"},
            {508, "Loop Detected"},
            {510, "Not Extended"},
            {511, "Network Authentication Required"}};

        // 查找状态码并返回对应描述
        auto it = status_msg.find(status);
        if (it != status_msg.end())
        {
            return it->second;
        }
        return "Unknown Status Code"; // 未知状态码的默认返回
    }
    // 根据文件后缀获取文件类型
    static std::string ExtMime(const std::string &filename)
    {
        static std::unordered_map<std::string, std::string> mime_type_map = {
            // 文本类
            {"txt", "text/plain"},
            {"html", "text/html"},
            {"htm", "text/html"},
            {"css", "text/css"},
            {"js", "text/javascript"},
            {"json", "application/json"},
            {"xml", "application/xml"},
            {"csv", "text/csv"},
            {"md", "text/markdown"},
            {"rtf", "application/rtf"},

            // 图像类
            {"jpg", "image/jpeg"},
            {"jpeg", "image/jpeg"},
            {"png", "image/png"},
            {"gif", "image/gif"},
            {"bmp", "image/bmp"},
            {"tiff", "image/tiff"},
            {"svg", "image/svg+xml"},
            {"ico", "image/x-icon"},
            {"webp", "image/webp"},
            {"avif", "image/avif"},

            // 音频类
            {"mp3", "audio/mpeg"},
            {"wav", "audio/wav"},
            {"ogg", "audio/ogg"},
            {"flac", "audio/flac"},
            {"aac", "audio/aac"},
            {"wma", "audio/x-ms-wma"},
            {"m4a", "audio/mp4"},

            // 视频类
            {"mp4", "video/mp4"},
            {"avi", "video/x-msvideo"},
            {"mkv", "video/x-matroska"},
            {"mov", "video/quicktime"},
            {"flv", "video/x-flv"},
            {"wmv", "video/x-ms-wmv"},
            {"mpeg", "video/mpeg"},
            {"mpg", "video/mpeg"},
            {"webm", "video/webm"},

            // 文档类
            {"pdf", "application/pdf"},
            {"doc", "application/msword"},
            {"docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
            {"xls", "application/vnd.ms-excel"},
            {"xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
            {"ppt", "application/vnd.ms-powerpoint"},
            {"pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
            {"odt", "application/vnd.oasis.opendocument.text"},
            {"ods", "application/vnd.oasis.opendocument.spreadsheet"},

            // 压缩文件类
            {"zip", "application/zip"},
            {"rar", "application/vnd.rar"},
            {"7z", "application/x-7z-compressed"},
            {"tar", "application/x-tar"},
            {"gz", "application/gzip"},
            {"bz2", "application/x-bzip2"},
            {"iso", "application/x-iso9660-image"},

            // 程序与脚本类
            {"c", "text/x-c"},
            {"cpp", "text/x-c++"},
            {"h", "text/x-c-header"},
            {"java", "text/x-java-source"},
            {"py", "text/x-python"},
            {"php", "application/x-httpd-php"},
            {"sh", "application/x-sh"},
            {"bat", "application/x-msdownload"},
            {"exe", "application/x-msdownload"},
            {"dll", "application/x-msdownload"},
            {"so", "application/octet-stream"},
            {"lib", "application/octet-stream"},

            // 其他常见格式
            {"pdf", "application/pdf"},
            {"log", "text/plain"},
            {"cfg", "text/plain"},
            {"ini", "text/plain"},
            {"sql", "application/sql"},
            {"db", "application/octet-stream"},
            {"sqlite", "application/x-sqlite3"},
            {"swf", "application/x-shockwave-flash"},
            {"ttf", "font/ttf"},
            {"woff", "font/woff"},
            {"woff2", "font/woff2"}};
        DEBUG_LOG("文件名:%s",filename.c_str());
        size_t pos = filename.find_last_of('.');
        if (pos == std::string::npos)
        {
            DEBUG_LOG("没有找到'.',退出");
            return "application/octet-stream"; // 返回一个二进制流，表示文件类型是一个二进制文件
        }
            
        std::string extension(filename.substr(pos + 1));
        DEBUG_LOG("文件扩展名为:%s",extension.c_str());
        // 查找扩展名并返回对应MIME类型
        auto it = mime_type_map.find(extension);
        if (it != mime_type_map.end())
        {
            return it->second;
        }
        return "application/octet-stream"; // 未知类型的默认MIME类型（二进制流）
    }
    // 判断文件是否是一个普通文件
    static bool IsRegular(const std::string &filename)
    {
        struct stat st;
        int ret = stat(filename.c_str(), &st);
        if (ret < 0)
            return false;
        return S_ISREG(st.st_mode);
    }
    // 判断文件是否是一个目录
    static bool IsDirectory(const std::string &filename)
    {
        struct stat st;
        int ret = stat(filename.c_str(), &st);
        if (ret < 0)
            return false;
        return S_ISDIR(st.st_mode);
    }
    // http请求的资源路径有效性判断
    static bool ValidPath(const std::string &path)
    {
        std::vector<std::string> spli;
        int count = Split(path, "/", spli);
        int level = 0;
        for (auto &e : spli)
        {
            if (e == "..")
                --level;
            else if (e != ".")
                ++level;
            if (level < 0)
                return false;
        }
        return true;
    }
};

class HttpRequest
{
public:
    HttpRequest():_version("HTTP/1.1"){}
    void ReSet()
    {
        _method.clear();
        _path.clear();
        _version="HTTP/1.1";
        _body.clear();
        std::smatch match;
        _matches.swap(match);
        _headers.clear();
        _params.clear();
    }
    void SetHeader(const std::string &key, const std::string &val)
    {
        _headers[key] = val;
    }
    bool HasHeader(const std::string &key) const
    {
        auto it = _headers.find(key);
        return it != _headers.end();
    }
    std::string GetHeader(const std::string &key) const
    {
        auto it = _headers.find(key);
        if (it != _headers.end())
            return it->second;
        return "";
    }
    void SetParam(const std::string &key, const std::string &val)
    {
        _params[key] = val;
    }
    bool HasParam(const std::string &key) const
    {
        auto it = _params.find(key);
        return it != _params.end();
    }
    std::string GetParam(const std::string &key) const
    {
        auto it = _params.find(key);
        if (it != _params.end())
            return it->second;
        return "";
    }
    size_t ContentLength() const
    {
        bool ret = HasHeader("Content-Length");
        if (ret == false)
        {
            DEBUG_LOG("没有设置请求正文");
            return 0;
        }
        return std::stoi(GetHeader("Content-Length"));
    }
    // 判断是否是短连接需要close
    bool Close() const
    {
        // 没有Connection字段或者有但是字段的值为close
        bool ret = HasHeader("Connection");
        if (ret == false || GetHeader("Connection") == "close")
            return true;
        // 有值并且字段值为keep_alive则为长连接
        return false;
    }

public:
    std::string _method;                                   // 请求方法
    std::string _path;                                     // 请求路径
    std::string _version;                                  // http版本
    std::string _body;                                     // 请求正文
    std::smatch _matches;                                  // 正则提取资源路径
    std::unordered_map<std::string, std::string> _headers; // 头部字段
    std::unordered_map<std::string, std::string> _params;  // 查询字符串键值对
};

class HttpResponse
{
public:
    HttpResponse() : _statu(200), _redirect_flag(false) {}
    HttpResponse(int statu) : _statu(statu), _redirect_flag(false) {}
    void ReSet()
    {
        _statu = 200;
        _redirect_flag = false;
        _body.clear();
        _redirect_url.clear();
        _headers.clear();
    }
    void SetHeader(const std::string &key, const std::string &val)
    {
        _headers[key] = val;
    }
    bool HasHeader(const std::string &key) const
    {
        auto it = _headers.find(key);
        if (it == _headers.end())
            return false;
        return true;
    }
    std::string GetHeader(const std::string &key) const
    {
        auto it = _headers.find(key);
        if (it == _headers.end())
            return "";
        return it->second;
    }
    void SetContent(const std::string &body, const std::string &type = "text/html")
    {
        _body = body;
        SetHeader("Content-Type", type);
    }
    void SetRedirect(const std::string &url, int statu = 302) // 临时重定向
    {
        _redirect_url = url;
        _statu = statu;
        _redirect_flag = true;
    }
    bool Close() const
    {
        // 没有Connection字段或者有但是字段的值为close
        bool ret = HasHeader("Connection");
        if (ret == false || GetHeader("Connection") == "close")
            return true;
        // 有值并且字段值为keep_alive则为长连接
        return false;
    }
public:
    int _statu;
    bool _redirect_flag;
    std::string _body;
    std::string _redirect_url;
    std::unordered_map<std::string, std::string> _headers;
};

enum HttpRecvStatu
{
    RECV_HTTP_ERR,
    RECV_HTTP_LINE,
    RECV_HTTP_HEAD,
    RECV_HTTP_BODY,
    RECV_HTTP_OVER
};

#define MAXLINE 8192

class HttpContext
{
public:
    HttpContext() : _resp_statu(200), _recv_statu(RECV_HTTP_LINE) {}
    int RespStatu() { return _resp_statu; }
    void Reset()
    {
        _resp_statu=200;
        _recv_statu=RECV_HTTP_LINE;
        _request.ReSet();
    }
    HttpRecvStatu RecvStatu() { return _recv_statu; }
    HttpRequest &Request() { return _request; }
    // 接收并解析http请求
    void RecvRequest(Buffer &buff)
    {
        // 不用break，因为处理完之后应该继续处理后面，因为有可能一次就将全部请求信息发送完了
        switch (_recv_statu)
        {
        case RECV_HTTP_LINE:
            RecvHttpLine(buff);
        case RECV_HTTP_HEAD:
            RecvHttpHead(buff);
        case RECV_HTTP_BODY:
            RecvhttpBody(buff);
        }
    }

private:
    bool RecvHttpLine(Buffer &buff)
    {
        if (_recv_statu != RECV_HTTP_LINE)
            return false;
        // 获取一行数据
        std::string line = buff.GetlineAndPop(); // 读取出错就直接退出关闭连接了，所以不用关心数据问题
        if (line.size() == 0)
        {
            // 缓冲区数据不足一行，则需要判断缓冲区的可读数据长度，如果很长都不足一行则数据有问题
            if (buff.ReadAbleSize() > MAXLINE)
            {
                DEBUG_LOG("数据过大退出");
                abort();
                _resp_statu = 414;
                _recv_statu = RECV_HTTP_ERR;
                return false;
            }
            // 不足一行但是也不多就再等等
            return true;
        }
        if (line.size() > MAXLINE)
        {
            DEBUG_LOG("数据过大退出");
            abort();
            _resp_statu = 414;
            _recv_statu = RECV_HTTP_ERR;
            return false;
        }
        bool ret = PrasehttpLine(line);
        if (ret == false)
        {
            ERROR_LOG("解析首行失败退出");
            //abort();
            return false;
        }
            
        _recv_statu = RECV_HTTP_HEAD;
        return true;
    }
    bool parase(const std::string& src,std::vector<std::string>& s)
    {
        size_t idx=0,pos=0;
        //请求方法查找
        pos=src.find(" ",idx);//寻找方法结尾
        if(pos==std::string::npos)
            return false;
        std::string method=src.substr(idx,pos-idx);
        std::transform(method.begin(),method.end(),method.begin(),toupper);
        if(method!="GET"&&method!="POST"&&method!="DELETE"&&method!="HEAD"&&method!="PUT")
        {
            DEBUG_LOG("请求方法匹配失败");
            return false;
        }
        s.push_back(std::move(method));
        //资源路径查找
        idx=pos+1;
        pos=src.find("?",idx);//是否存在头部字段
        if(pos==std::string::npos)
        {
            pos=src.find(" ",idx);
            if(pos==std::string::npos)
            {
                DEBUG_LOG("资源路径不存在");
                return false;
            }
        }
        std::string uri=src.substr(idx,pos-idx);
        s.push_back(std::move(uri));//右值引用减少拷贝
        //头部字段查找
        if(src[pos]!='?')//没有头部字段
            s.push_back("");
        else//有头部字段
        {
            idx=pos+1;
            pos=src.find(" ",idx);//找结尾
            if(pos==std::string::npos)
            {
                DEBUG_LOG("头部字段异常");
                return false;
            }
                
            std::string query=src.substr(idx,pos-idx);
            s.push_back(std::move(query));
        }
        //http版本
        idx=pos+1;
        if(src.back()=='\n')
        {
            std::string http_version;
            if(src[src.size()-2]=='\r')
                http_version=src.substr(idx,src.size()-2-idx);
            else
                http_version=src.substr(idx,src.size()-1-idx);
            s.push_back(std::move(http_version));
        }
        return true;
    }
    bool PrasehttpLine(const std::string &src)
    {
        // std::smatch s;
        // //设置标志位 std::regex:icase忽略大小写
        // DEBUG_LOG("正则:%s",src.c_str());
        // std::regex reg("(GET|POST|DELETE|HEAD|PUT) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\n|\r\n)?",std::regex::icase);
        // bool ret = std::regex_match(src, s, reg);
        // if (ret == false)
        // {
        //     DEBUG_LOG("正则匹配失败退出");
        //     //abort();
        //     _resp_statu = 400; // bad request
        //     _recv_statu = RECV_HTTP_ERR;
        //     return false;
        // }
        std::vector<std::string> s;
        bool ret=parase(src,s);
        if(ret==false)
        {
            DEBUG_LOG("匹配请求行失败");
            _resp_statu = 400; // bad request
            _recv_statu = RECV_HTTP_ERR;
            return false;
        }
        _request._method=std::move(s[0]);//请求方法
        std::transform(_request._method.begin(),_request._method.end(),_request._method.begin(),toupper);
        // 资源路径的获取需要经过url解码操作，但是不需要将+转空格，转空格仅发生在查询字符串
        _request._path = Util::URLDecode(s[1], false);
        _request._version = std::move(s[3]);//http版本
        std::vector<std::string> query_string_array;
        std::string query(std::move(s[2]));//头部字段
        Util::Split(query, "&", query_string_array);
        // 查询字符串格式key=val&key1=val2&...
        // 先按照'&'进行分割，形成以'='为间隔符需要进行分割的子串
        for (auto &str : query_string_array)
        {
            size_t pos = str.find('=');
            if (pos == std::string::npos)
            {
                DEBUG_LOG("找不到'='失败退出");
                abort();
                _resp_statu = 400; // bad request
                _recv_statu = RECV_HTTP_ERR;
                return false;
            }
            _request.SetParam(Util::URLDecode(str.substr(0, pos), true), Util::URLDecode(str.substr(pos + 1), true));
        }
        return true;
    }
    bool RecvHttpHead(Buffer &buff)
    {
        if (_recv_statu != RECV_HTTP_HEAD)
            return false;
        // 一行一行取出，直到遇到空行,格式   key: val\r\n
        while (1)
        {
            std::string line = buff.GetlineAndPop(); // 读取出错就直接退出关闭连接了，所以不用关心数据问题
            if (line.size() == 0)
            {
                // 缓冲区数据不足一行，则需要判断缓冲区的可读数据长度，如果很长都不足一行则数据有问题
                if (buff.ReadAbleSize() > MAXLINE)
                {
                    DEBUG_LOG("数据太长失败退出");
                    abort();
                    _resp_statu = 414;
                    _recv_statu = RECV_HTTP_ERR;
                    return false;
                }
                // 不足一行但是也不多就再等等
                return true;
            }
            if (line.size() > MAXLINE)
            {
                DEBUG_LOG("数据太长失败退出");
                abort();
                _resp_statu = 414;
                _recv_statu = RECV_HTTP_ERR;
                return false;
            }
            if (line == "\n" || line == "\r\n")
                break;
            bool ret = PrasehttpHead(line);
            if (ret == false)
            {
                DEBUG_LOG("解析头部字段失败退出");
                abort();
                return false;
            }
                
        }
        // 头部处理完毕，进入正文
        _recv_statu = RECV_HTTP_BODY;
        return true;
    }
    bool PrasehttpHead(const std::string &src)
    {
        std::string head=src;
        if(head.back()=='\n')
            head.pop_back();
        if(head.back()=='\r')
            head.pop_back();
        size_t pos = head.find(": ");
        if (pos == std::string::npos)
        {
            DEBUG_LOG("找不到': '失败退出");
            abort();
            _resp_statu = 414;
            _recv_statu = RECV_HTTP_ERR;
            return false;
        }
        std::string key = head.substr(0, pos);
        std::string val = head.substr(pos + 2);
        //DEBUG_LOG("key:%s   val:%s",key.c_str(),val.c_str());
        _request.SetHeader(key, val);
        return true;
    }
    bool RecvhttpBody(Buffer &buff)
    {
        if (_recv_statu != RECV_HTTP_BODY)
            return false;
        //DEBUG_LOG("开始接受请求正文");
        // 获取正文长度
        size_t content_length = _request.ContentLength();
        DEBUG_LOG("长度:%ld",content_length);
        if (content_length == 0)
        {
            _recv_statu = RECV_HTTP_OVER;
            return true;
        }
        // 当前还需要接受的正文长度
        size_t real_len = content_length - _request._body.size();
        // 接收正文到body中，也要考虑当前缓冲区中的数据是否是全部正文
        if (buff.ReadAbleSize() >= real_len)
        {
            _request._body.append(buff.Read_Position(), real_len);
            buff.MoveReadOffset(real_len);
            _recv_statu = RECV_HTTP_OVER;
            return true;
        }
        _request._body.append(buff.Read_Position(), buff.ReadAbleSize());
        buff.MoveReadOffset(buff.ReadAbleSize());
        return true;
    }

private:
    int _resp_statu;
    HttpRecvStatu _recv_statu;
    HttpRequest _request;
};

class HttpServer
{
public:
    using Handle=std::function<void(const HttpRequest &req, HttpResponse &rsp)>;
    using Handlers=std::vector<std::pair<std::regex, Handle>>;
    HttpServer(int port,int timeout=DEFAULT_TIMEOUT):_server(port)
    {
        _server.EnableInactiveRelease(timeout);
        _server.SetConnectedCallback(std::bind(&HttpServer::OnConnected,this,std::placeholders::_1));
        _server.SetMessageCallback(std::bind(&HttpServer::OnMessage,this,std::placeholders::_1,std::placeholders::_2));
    }
    void Get(const std::string &pattern, const Handle &handle)
    {
        //此处不能忽略大小写，资源路径是绝对的
        _get_route.emplace_back(std::make_pair(std::regex(pattern),handle));
    }
    void Post(const std::string &pattern, const Handle &handle)
    {
        _post_route.emplace_back(std::make_pair(std::regex(pattern),handle));
    }
    void Put(const std::string &pattern, const Handle &handle)
    {
        _put_route.emplace_back(std::make_pair(std::regex(pattern),handle));
    }
    void Delete(const std::string &pattern, const Handle &handle)
    {
        _delete_route.emplace_back(std::make_pair(std::regex(pattern),handle));
    }
    void SetBaseDir(const std::string &path)
    {
        assert(Util::IsDirectory(path));
        _basedir=path;
    }
    void SetThreadCount(int count)
    {
        _server.SetThreadCount(count);
    }
    void Listen()
    {
        _server.Start();
    }

private:
    void ErrorHandle(const HttpRequest &req, HttpResponse &rsp)
    {
        //组织一个错误展示页面
        //将页面数据作为响应正文放入rsp中
        std::string body="<html>";
        body+="<head>";
        body+="<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>";
        body+="</head>";
        body+="<body>";
        body+="<h1>";
        body+=std::to_string(rsp._statu);
        body+=" ";
        body+=Util::StatusDesc(rsp._statu);
        body+="</h1>";
        body+="</body>";
        body+="</html>";
        rsp.SetContent(body);
    }
    void OnConnected(const PtrConnection &conn) // 设置上下文
    {
        conn->SetContext(HttpContext()); // 设置上下文类型
        DEBUG_LOG("new connection%p", conn.get());
    }
    void OnMessage(const PtrConnection &conn, Buffer *buf) // 缓冲区数据解析并处理
    {
        DEBUG_LOG("接收到数据");
        while (buf->ReadAbleSize() > 0)
        {
            // 获取上下文
            //INFO_LOG("收到数据长度:%ld",buf->ReadAbleSize());
            HttpContext &context = std::any_cast<HttpContext &>(*conn->GetContext());
            // 经过解析，获取到httprequest
            context.RecvRequest(*buf);
            HttpResponse rsp(context.RespStatu());
            HttpRequest &req = context.Request();
            // 解析出错，响应出错信息
            if (context.RespStatu() >= 400)
            {
                // 响应出错，关闭连接
                ErrorHandle(req, rsp);
                WriteResponse(req, rsp, conn);
                context.Reset();//重置上下文，才能够不断清除缓冲区数据，缓存区数据清空自然退出
                buf->MoveReadOffset(buf->ReadAbleSize());//我们也可以选择出错后将缓冲区全部数据清空，这样shutdown就会直接断开连接
                DEBUG_LOG("响应出错，关闭连接");
                return conn->ShutDown();//shutdonw功能为取完数据并且没有可写才退出
            }
            // 解析正常且请求获取完毕才开始处理
            if (context.RecvStatu() != RECV_HTTP_OVER)
            {
                // 当前请求还没有接收完整 ,退出等新数据到来
                DEBUG_LOG("当前请求还没有接收完整 ,退出等新数据到来");
                return;
            }
            // 请求路由+业务处理
            DEBUG_LOG("开始进行业务处理");
            DEBUG_LOG("请求正文:%s",req._body.c_str());
            Route(req, rsp);
            // 对httpresponse进行组织发送
            WriteResponse(req, rsp, conn);
            //重置上下文
            context.Reset();
            // 根据长短连接判断是否要关闭连接
            if (rsp.Close())
            {
                DEBUG_LOG("短连接关闭连接");
                return conn->ShutDown();
            }
        }
    }
    void Route(HttpRequest &req, HttpResponse &rsp)
    {
        // 对请求进行分辨，是静态资源还是功能性请求
        // Get,Head都默认是静态资源型请求
        //功能性请求则需要通过请求路由表来确定是否有处理函数
        //既不是静态资源，也没有对应的函数，则返回404
        bool ret = IsFileHandle(req);
        if (ret == true)
            return FileHanle(req,rsp);
        if(req._method=="GET"||req._method=="HEAD")
            return Diapatcher(req, rsp,_get_route);
        else if(req._method=="POST")
            return Diapatcher(req, rsp,_post_route);
        else if(req._method=="PUT")
            return Diapatcher(req, rsp,_put_route);
        else if(req._method=="DELETE")
            return Diapatcher(req, rsp,_delete_route);
        DEBUG_LOG("业务处理寻找失败");
        rsp._statu=405;//method not allow
    }
    bool IsFileHandle(const HttpRequest &req)
    {
        //必须设置了静态资源根目录
        if(_basedir.empty())
            return false;
        //请求方法必须是get或head
        if(req._method!="GET"&&req._method!="HEAD")
            return false;
        //请求资源必须是一个合法的路径
        if(Util::ValidPath(req._path)==false)
            return false;
        //请求的资源必须存在
        //有一种情况比较特殊，'/'，纯粹的相对根目录，这种情况默认给后面追加一个/index.html
        //还要注意前缀根目录，也就是将请求路径转化为实际存在的路径
        std::string path=_basedir+req._path;//为避免直接修改，仅仅当确认的时候再追加
        if(req._path.back()=='/')
            path+="index.html";
        if(Util::IsRegular(path)==false)
            return false;
        //req._path=path;//有可能没有追加
        return true;
    }
    // 静态资源请求处理,获取并放到body中，并设置Content-Type
    void FileHanle(const HttpRequest &req, HttpResponse &rsp)
    {
        DEBUG_LOG("访问静态资源");
        std::string path=_basedir+req._path;
        if(path.back()=='/')
            path+="index.html";
        DEBUG_LOG("资源路径:%s",path.c_str());
        Buffer buf;
        bool ret=Util::ReadFile(path,buf);
        if(ret==false)
            return;
        DEBUG_LOG("成功获取到静态资源");
        rsp._body=buf.ReadAsString(buf.ReadAbleSize());
        std::string MIME=Util::ExtMime(path);
        DEBUG_LOG("资源类型:%s",MIME.c_str());
        rsp.SetHeader("Content-Type",MIME);
        return;
    }
    void Diapatcher(HttpRequest &req, HttpResponse &rsp,Handlers& handlers) // 功能性请求的分类处理
    {
        for(auto& handle:handlers)
        {
            //正则表达式编译需要时间，因此我们将哈希表存储由string修改为regex
            const std::regex& reg=handle.first;
            const Handle& functor=handle.second;
            bool ret=std::regex_match(req._path,req._matches,reg);
            if(ret==false)
                continue;
            return functor(req,rsp);//传入请求信息与空的rsp
        }
        rsp._statu=404;
    }
    // 将httpresponse中的数据按照协议格式进行组织发送
    void WriteResponse(const HttpRequest &req, HttpResponse &rsp, const PtrConnection &conn)
    {
        //先完善头部字段
        if(req.Close())
            rsp.SetHeader("Connection","close");
        else
            rsp.SetHeader("Connection","keep-alive");
        if(rsp._body.empty()==false && rsp.HasHeader("Content-Length")==false)
        {
            rsp.SetHeader("Content-Length",std::to_string(rsp._body.size()));
        }
        if(rsp._body.empty()==false && rsp.HasHeader("Content-Type")==false)
        {
            rsp.SetHeader("Content-Type","application/octet-stream");
        }
        if(rsp._redirect_flag==true)
        {
            rsp.SetHeader("Location",rsp._redirect_url);
        }
        //组织数据并发送
        std::stringstream ss;
        ss<<req._version<<' '<<std::to_string(rsp._statu)<<' '<<Util::StatusDesc(rsp._statu)<<"\r\n";
        for(auto& e:rsp._headers)
        {
            ss<<e.first<<": "<<e.second<<"\r\n";
        }
        ss<<"\r\n";
        ss<<rsp._body;
        //INFO_LOG("发送数据:%s",ss.str().c_str());
        conn->Send(ss.str().c_str(),ss.str().size());
    }

private:
    TcpServer _server;
    Handlers _get_route;
    Handlers _post_route;
    Handlers _put_route;
    Handlers _delete_route;
    std::string _basedir; // 静态资源根目录，使用get访问
};